﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using iTeamyou.LTS.Core.Models;
using iTeamyou.LTS.Core.Utils;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;

namespace iTeamyou.LTS.Core.Services
{
	public class ProductService : IDataService<Product, ProductLicense>
	{
        public MainDBContext _dbContext;
        private readonly ILogger<Product> _logger;
        private Comparator _comparator;
        private ProductAttachmentService _attachmentService;
        public SharedService _sharedService = new SharedService();

        public ProductService()
        {
            _dbContext ??= new MainDBContext();
        }

        public ProductService(string connectionString)
        {
            _dbContext = new MainDBContext(new DbContextOptionsBuilder<MainDBContext>().UseMySql(connectionString, new MySqlServerVersion(new Version())).Options);
        }

        public ProductService(MainDBContext dbContext, ILogger<Product> logger, ProductAttachmentService attachmentService)
		{
            _dbContext = dbContext;
            _logger = logger;
            _comparator = new Comparator();
            _attachmentService = attachmentService;
        }

        public int Delete(IEnumerable<Product> products)
        {
            _dbContext.Products.RemoveRange(products);
            return _dbContext.SaveChanges();
        }

        public Product Get(string id)
        {
            return _dbContext.Products.AsNoTracking().FirstOrDefault(s => s.Id == id);
        }

        public Product GetByBarcode(string barcode)
        {
            return _dbContext.Products.AsNoTracking().FirstOrDefault(s => s.UPC == barcode);
        }

        public List<Product> GetByBarcodes(List<string> barcodes)
        {
            return _dbContext.Products.AsNoTracking().Where(p => barcodes.Contains(p.UPC)).ToList();
        }

        public Product GetBySKU(string sku)
        {
            return _dbContext.Products.AsNoTracking().FirstOrDefault(s => s.PId == sku);
        }

        public List<Product> GetBySkus(List<string> skus)
        {
            return _dbContext.Products.AsNoTracking().Where(p => skus.Contains(p.PId)).ToList();
        }

        public List<Product> Search(string key)
        {
            return _dbContext.Products.AsNoTracking().Where(s => s.Name == key || s.PId == key || s.UPC == key).ToList();
        }

        public List<Product> GetList()
        {
            var list = _dbContext.Products.AsNoTracking().OrderByDescending(s => s.LastModifiedOn).ToList();
            //if (list.Count > 0)
            //{
            //    foreach (var product in list)
            //    {
            //        product.ProductLicenses = GetLicensesById(product.Id);
            //    }
            //}

            return list;
        }

        public List<ExportProduct> GetExport()
        {
            var result = new List<ExportProduct>();
            var list = _dbContext.Products.AsNoTracking().OrderByDescending(s => s.LastModifiedOn).ToList();
            if (list.Count > 0)
            {
                foreach (var product in list)
                {
                    var export = new ExportProduct()
                    {
                        Id = product.PId,
                        Brand = product.Brand,
                        CreatedBy = product.CreatedBy,
                        CreatedOn = product.CreatedOn,
                        Department = GetProductDepartment(product.SectionId).Description,
                        LastModifiedOn = product.LastModifiedOn,
                        Name = product.Name,
                        OriginPlace = product.OriginPlace,
                        Specification = product.Specification,
                        UPC = product.UPC
                    };

                    var licenses = GetLicensesById(product.Id);
                    var urlList = new List<string>();
                    if (licenses.Count > 0)
                    {
                        foreach (var license in licenses)
                        {
                            var attachment = _attachmentService.GetList(license.Id, true).FirstOrDefault();
                            if (attachment != null)
                                urlList.Add(attachment.URL);
                            var otherAttachment = _attachmentService.GetList(license.Id, false);
                            if (otherAttachment != null && otherAttachment.Any())
                                otherAttachment.ForEach(o => urlList.Add(o.URL));
                        }
                    }
                    export.ProductLicenseUrl = urlList;
                    result.Add(export);
                }
            }
            return result;
        }

        public List<ExportProduct> GetExport(List<Product> products)
        {
            var result = new List<ExportProduct>();
            if (products.Count > 0)
            {
                foreach (var product in products)
                {
                    var export = new ExportProduct()
                    {
                        Id = product.PId,
                        Brand = product.Brand,
                        CreatedBy = product.CreatedBy,
                        CreatedOn = product.CreatedOn,
                        Department = GetProductDepartment(product.SectionId).Description,
                        LastModifiedOn = product.LastModifiedOn,
                        Name = product.Name,
                        OriginPlace = product.OriginPlace,
                        Specification = product.Specification,
                        UPC = product.UPC
                    };

                    var licenses = GetLicensesById(product.Id);
                    var urlList = new List<string>();
                    if (licenses.Count > 0)
                    {
                        foreach (var license in licenses)
                        {
                            var attachment = _attachmentService.GetList(license.Id, true).FirstOrDefault();
                            if (attachment != null)
                                urlList.Add(attachment.URL);
                            var otherAttachment = _attachmentService.GetList(license.Id, false);
                            if (otherAttachment != null && otherAttachment.Any())
                                otherAttachment.ForEach(o => urlList.Add(o.URL));
                        }
                    }
                    export.ProductLicenseUrl = urlList;
                    result.Add(export);
                }
            }
            return result;
        }

        //public List<ProductLicense> GetLicenseExport(List<ProductLicense> licenses)
        //{
        //    var result = new List<ProductLicense>();
        //    if (licenses.Count > 0)
        //    {
        //        foreach (var license in licenses)
        //        {
        //            var attachment = _attachmentService.GetList(license.Id, true).FirstOrDefault();
        //            if (attachment != null)
        //                license.Attachments.Add(attachment);
        //            var otherAttachment = _attachmentService.GetList(license.Id, false);
        //            if (otherAttachment != null && otherAttachment.Any())
        //                otherAttachment.ForEach(o => urlList.Add(o.URL));
        //            result.Add
        //        }
        //    }
        //    return result;
        //}

        public void Save(Product product)
        {
            var exists = _dbContext.Products.Where(g => g.Id == product.Id).FirstOrDefault();
            if (exists == null)
            {
                if (product.CreatedOn == null)
                    product.CreatedOn = DateTime.Now;
                _dbContext.Add(product);
            }
            else
            {
                exists.UPC = product.UPC;
                exists.Name = product.Name;
                exists.Specification = product.Specification;
                exists.Brand = product.Brand;
                exists.Department = product.Department;
                exists.Category = product.Category;
                exists.OriginPlace = product.OriginPlace;
                exists.LastModifiedBy = product.LastModifiedBy;
                exists.LastModifiedOn = product.LastModifiedOn;
                exists.SupplierId = product.SupplierId;
                //exists.ProductLicenses = product.ProductLicenses;
                //if (product.ProductLicenses != null && product.ProductLicenses.Count() > 0)
                exists.LicenseNum = _dbContext.ProductLicenses.AsNoTracking().Where(s => s.ProductId == product.Id && s.IsPublish == true).Count();
                exists.ProductLicenses = product.ProductLicenses;
                //SaveLicense(product.Id, product.ProductLicenses, product.LastModifiedBy);
                SaveLicense(exists);
            }
            _dbContext.SaveChanges();
        }
        //新增批量插入
        public void BatchSave(List<Product> productsToInsert)
        {
            Console.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}] 开始批量插入，共 {productsToInsert.Count} 条产品数据。");
            foreach (var product in productsToInsert)
            {
                var exists = _dbContext.Products.FirstOrDefault(g => g.Id == product.Id);
                if (exists == null)
                {
                    if (product.CreatedOn == null)
                        product.CreatedOn = DateTime.Now;
                    _dbContext.Add(product);
                }
                else
                {
                    exists.UPC = product.UPC;
                    exists.Name = product.Name;
                    exists.Specification = product.Specification;
                    exists.Brand = product.Brand;
                    exists.Department = product.Department;
                    exists.Category = product.Category;
                    exists.OriginPlace = product.OriginPlace;
                    exists.LastModifiedBy = product.LastModifiedBy;
                    exists.LastModifiedOn = product.LastModifiedOn;
                    exists.SupplierId = product.SupplierId;
                    exists.LicenseNum = _dbContext.ProductLicenses.AsNoTracking().Where(s => s.ProductId == product.Id && s.IsPublish == true).Count();
                    exists.ProductLicenses = product.ProductLicenses;
                    SaveLicense(exists);
                }
            }
            _dbContext.SaveChanges();
        }
        public void Update(Product product)
        {
            var exist = _dbContext.Products.Where(g => g.Id == product.Id).FirstOrDefault();
            if (exist == null)
                return;

            exist.PId = product.PId;
            exist.UPC = product.UPC;
            exist.Name = product.Name;
            exist.Specification = product.Specification;
            exist.Brand = product.Brand;
            exist.Department = product.Department;
            exist.Category = product.Category;
            exist.OriginPlace = product.OriginPlace;
            exist.LastModifiedBy = product.LastModifiedBy;
            exist.LastModifiedOn = product.LastModifiedOn;
            exist.SupplierId = product.SupplierId;
            _dbContext.SaveChanges();
        }
        //新增批量更新
        public void BatchUpdate1(List<Product> products)
        {
            Console.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}] 开始批量更新，共 {products.Count} 条产品数据。");
            foreach (var product in products)
            {
                var exist = _dbContext.Products.FirstOrDefault(g => g.Id == product.Id);
                if (exist != null)
                {
                    exist.PId = product.PId;
                    exist.UPC = product.UPC;
                    exist.Name = product.Name;
                    exist.Specification = product.Specification;
                    exist.Brand = product.Brand;
                    exist.Department = product.Department;
                    exist.Category = product.Category;
                    exist.OriginPlace = product.OriginPlace;
                    exist.LastModifiedBy = product.LastModifiedBy;
                    exist.LastModifiedOn = product.LastModifiedOn;
                    exist.SupplierId = product.SupplierId;
                }
            }
            _dbContext.SaveChanges();
        }
        public void BatchUpdate(List<Product> products)
        {
            Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 开始批量更新，共 {products.Count} 条产品数据。");

            const int batchSize = 5000;
            for (int i = 0; i < products.Count; i += batchSize)
            {
                var batch = products.Skip(i).Take(batchSize).ToList();

                var existingProducts = _dbContext.Products.Where(p => batch.Select(b => b.Id).Contains(p.Id)).ToDictionary(p => p.Id); // 转为字典加速查找

                foreach (var product in batch)
                {
                    if (existingProducts.TryGetValue(product.Id, out var exist))
                    {
                        _dbContext.Entry(exist).CurrentValues.SetValues(product);
                    }
                }
                _dbContext.SaveChanges();
            }
        }

        public List<ProductLicense> GetLicenses(List<ProductLicense>? licenses = null)
        {
            var result = new List<ProductLicense>();
            if (licenses != null && licenses.Any())
                result = licenses;
            else
                result = _dbContext.ProductLicenses.AsNoTracking().Where(l => l.IsPublish == true).ToList();

            foreach (var license in result)
            {
                if (license.ValidToDate != null)
                    license.RemainingDays = ((DateTime)license.ValidToDate - DateTime.Now).Days;

                //var attachment = _attachmentService.GetList(license.Id, true).FirstOrDefault();
                //var licenseList = new List<string>();
                //if (attachment != null)
                //    licenseList.Add(attachment.URL);
                //var otherAttachment = _attachmentService.GetList(license.Id, false);
                //if (otherAttachment != null && otherAttachment.Any())
                //    otherAttachment.ForEach(o => licenseList.Add(o.URL));

                //license.AttachmentURL = licenseList;
            }
            return result;
        }

        public List<ProductLicense> GetLicensesExport(List<ProductLicense>? licenses = null)
        {
            var result = new List<ProductLicense>();
            if (licenses != null && licenses.Any())
                result = licenses;
            else
                result = _dbContext.ProductLicenses.AsNoTracking().Where(l => l.IsPublish == true).ToList();

            foreach (var license in result)
            {
                if (license.ValidToDate != null)
                    license.RemainingDays = ((DateTime)license.ValidToDate - DateTime.Now).Days;

                var attachment = _attachmentService.GetList(license.Id, true).FirstOrDefault();
                var licenseList = new List<string>();
                if (attachment != null)
                    licenseList.Add(attachment.URL);
                var otherAttachment = _attachmentService.GetList(license.Id, false);
                if (otherAttachment != null && otherAttachment.Any())
                    otherAttachment.ForEach(o => licenseList.Add(o.URL));

                license.AttachmentURL = licenseList;
            }
            return result;
        }

        public int GetLicenseCount()
        {
            return _dbContext.ProductLicenses.Count(l => l.IsPublish == true);
        }

        public List<ProductLicense> GetLicensesById(string id)
        {
            return _dbContext.ProductLicenses.AsNoTracking().Where(s => s.ProductId == id && s.IsPublish == true).ToList();
        }

        public ProductLicense GetLicenseByLId(string lid)
        {
            return _dbContext.ProductLicenses.AsNoTracking().Where(s => s.LId == lid).FirstOrDefault();
        }

        public List<LicenseType> GetLicenseType(string type = "")
        {
            if (string.IsNullOrEmpty(type))
                return _dbContext.LicenseTypes.AsNoTracking().ToList();
            return _dbContext.LicenseTypes.AsNoTracking().Where(l => l.Module == type).ToList();
        }

        public List<ProductHierarchy> GetProductCategories()
        {
            return _dbContext.ProductHierarchies.AsNoTracking().Where(p => p.Level == HierarchyLevel.Category).ToList();
        }

        public List<ProductHierarchy> GetProductDepartments()
        {
            return _dbContext.ProductHierarchies.AsNoTracking().Where(p => p.Level == HierarchyLevel.Department).ToList();
        }

        public List<string?> GetProductBrands()
        {
            return _dbContext.Products.AsNoTracking().Select(p => p.Brand).Distinct().OrderBy(p => p).ToList();
        }

        public ProductHierarchy GetProductDepartment(string sectionId)
        {
            //var product = _dbContext.Products.Where(predicate: p => p.PId == productId).FirstOrDefault();
            //if (product == null || string.IsNullOrEmpty(product.SectionId) || product.SectionId.Length < 8)
            if (string.IsNullOrEmpty(sectionId) || sectionId.Length < 8)
                return new ProductHierarchy() { Description = "暂无分类" };
            var departmentId = sectionId.Substring(0, 2);
            return GetProductHierarchy(departmentId, HierarchyLevel.Department);
        }

        public ProductHierarchy GetProductCategory(string productId)
        {
            var product = _dbContext.Products.Where(predicate: p => p.PId == productId).FirstOrDefault();
            if (product == null || string.IsNullOrEmpty(product.SectionId) || product.SectionId.Length < 8)
                return new ProductHierarchy() { Description = "暂无分类" };
            var departmentId = product.SectionId.Substring(0, 4);
            return GetProductHierarchy(departmentId, HierarchyLevel.Category);
        }

        public ProductHierarchy GetProductHierarchy(string id, HierarchyLevel level)
        {
            var result = _dbContext.ProductHierarchies.AsNoTracking().Where(predicate: l => l.Id == id && l.Level == level).FirstOrDefault();
            return result ?? new ProductHierarchy() { Description = "暂无分类" };
        }

        //private void SaveLicense(string id, List<ProductLicense> licenses, string userId)
        private void SaveLicense(Product product)
        {
            var licenses = product.ProductLicenses;
            var id = product.Id;
            var userId = product.LastModifiedBy;

            var exists = _dbContext.ProductLicenses.AsNoTracking().Where(s => s.ProductId == id && s.IsPublish == true).OrderBy(s => s.Id).ToList();
            var licensesCompare = licenses.OrderBy(l => l.Id).ToList();
            if (_comparator.DifferenceComparison(exists, licensesCompare))
            {
                //发起流程
                var currentTbId = "fd_3c7343ed25a0e8";
                var historyTbId = "fd_3c7344bbcb4a6c";
                var flowService = new EKPFlowService();
                var formValues = new string("{\"fd_3c73440309699e\":\"" + product.Name + "\", \"fd_3c734404052200\":\"" + product.PId + "\",");
                var tbValue1 = $"\"{currentTbId}.fd_3c7344a1863166\":[";
                var tbValue2 = $"\"{currentTbId}.fd_3c7491d44ed0da\":[";
                var tbValue3 = $"\"{currentTbId}.fd_3c7491d84aabe6\":[";
                var tbValue4 = $"\"{currentTbId}.fd_3c7344a53921c2\":[";
                var tbValue5 = $"\"{currentTbId}.fd_3c7344a7ced6b2\":[";
                var tbValue6 = $"\"{currentTbId}.fd_3c7344a67ef9e8\":[";

                var tbHistoryValue1 = $"\"{historyTbId}.fd_3c7344e5124b46\":[";
                var tbHistoryValue2 = $"\"{historyTbId}.fd_3c749202cd5272\":[";
                var tbHistoryValue3 = $"\"{historyTbId}.fd_3c749204297b04\":[";
                var tbHistoryValue4 = $"\"{historyTbId}.fd_3c7344e8f4f4b6\":[";
                var tbHistoryValue5 = $"\"{historyTbId}.fd_3c7344ea331368\":[";

                if (exists != null && exists.Any())
                {
                    exists.ForEach(e =>
                    {
                        var attachmentURL = string.Empty;
                        var attachment = e.Attachments?.FirstOrDefault(l => l.IsMain == true);
                        if (attachment != null)
                            attachmentURL = attachment.URL;

                        tbHistoryValue1 += "\"" + GetLicenseTypeName(e.Type, "product") + "\",";
                        tbHistoryValue2 += "\"" + ((DateTime)e.ValidFromDate).ToString("yyyy-MM-dd") + "\",";
                        tbHistoryValue3 += "\"" + ((DateTime)e.ValidToDate).ToString("yyyy-MM-dd") + "\",";
                        tbHistoryValue4 += "\"" + e.LId + "\",";
                        tbHistoryValue5 += "\"" + attachmentURL + "\",";
                    });

                    tbHistoryValue1 = tbHistoryValue1.Remove(tbHistoryValue1.LastIndexOf(","), 1) + "],";
                    tbHistoryValue2 = tbHistoryValue2.Remove(tbHistoryValue2.LastIndexOf(","), 1) + "],";
                    tbHistoryValue3 = tbHistoryValue3.Remove(tbHistoryValue3.LastIndexOf(","), 1) + "],";
                    tbHistoryValue4 = tbHistoryValue4.Remove(tbHistoryValue4.LastIndexOf(","), 1) + "],";
                    tbHistoryValue5 = tbHistoryValue5.Remove(tbHistoryValue5.LastIndexOf(","), 1) + "],";
                    formValues += tbHistoryValue1 + tbHistoryValue2 + tbHistoryValue3 + tbHistoryValue4 + tbHistoryValue5;
                }

                if (licenses != null && licenses.Any())
                {
                    licenses.ForEach(license =>
                    {
                        var existLicense = exists.FirstOrDefault(l => l.Id == license.Id);
                        if (string.IsNullOrEmpty(license.Id) || _comparator.DifferenceEntityComparison(existLicense, license))
                        {
                            if (exists.Any(e => e.Id == license.Id) && license.OperationType != LicenseOp.Delete)
                                license.OperationType = LicenseOp.Modify;
                            else if (license.OperationType != LicenseOp.Delete)
                                license.OperationType = LicenseOp.Add;

                            if (string.IsNullOrEmpty(license.CreatedBy))
                                license.CreatedBy = userId;

                            license.Id = Guid.NewGuid().ToString("N");
                            license.IsPublish = false;

                            license.Attachments?.ForEach(a =>
                            {
                                a.Id = Guid.NewGuid().ToString("N");
                                a.LicenseId = license.Id;
                                _dbContext.ProductLicenseAttachments.Add(a);
                            });

                            var opTypeString = "";
                            if (license.OperationType == LicenseOp.Add)
                                opTypeString = "新增";
                            else if (license.OperationType == LicenseOp.Modify)
                                opTypeString = "修改";
                            else if (license.OperationType == LicenseOp.Delete)
                                opTypeString = "删除";

                            var attachmentURL = string.Empty;
                            var attachment = license.Attachments?.FirstOrDefault(l => l.IsMain == true);
                            if (attachment != null)
                                attachmentURL = attachment.URL;

                            tbValue1 += "\"" + GetLicenseTypeName(license.Type, "product") + "\",";
                            tbValue2 += "\"" + ((DateTime)license.ValidFromDate).ToString("yyyy-MM-dd") + "\",";
                            tbValue3 += "\"" + ((DateTime)license.ValidToDate).ToString("yyyy-MM-dd") + "\",";
                            tbValue4 += "\"" + license.LId + "\",";
                            tbValue5 += "\"" + opTypeString + "\",";
                            tbValue6 += "\"" + attachmentURL + "\",";

                            license.Attachments = new List<ProductLicenseAttachment>();
                        }
                    });

                    tbValue1 = tbValue1.Remove(tbValue1.LastIndexOf(","), 1) + "],";
                    tbValue2 = tbValue2.Remove(tbValue2.LastIndexOf(","), 1) + "],";
                    tbValue3 = tbValue3.Remove(tbValue3.LastIndexOf(","), 1) + "],";
                    tbValue4 = tbValue4.Remove(tbValue4.LastIndexOf(","), 1) + "],";
                    tbValue5 = tbValue5.Remove(tbValue5.LastIndexOf(","), 1) + "],";
                    tbValue6 = tbValue6.Remove(tbValue6.LastIndexOf(","), 1) + "]";
                    formValues += tbValue1 + tbValue2 + tbValue3 + tbValue4 + tbValue5 + tbValue6 + "}";
                    var flowId = flowService.AddReview(_sharedService.GetConfig("EKPProductLicenseTemplateId"), "商品证照更新", userId, formValues);

                    licenses.ForEach(l => l.RefFlowId = flowId);
                    _dbContext.ProductLicenses.AddRange(licenses);
                }
                //else //todo: 观察
                //    _dbContext.ProductLicenses.RemoveRange(exists);

                _dbContext.SaveChanges();
            }
        }

        public void UploadLicense(ProductLicense license)
        {
            _dbContext.ProductLicenses.Add(license);
            _dbContext.SaveChanges();
        }

        public void LicenseStatistics()
        {
            var products = GetList();
            if (products.Any())
            {
                foreach (var product in products)
                {
                    var licenses = GetLicensesById(product.Id);
                    if (licenses.Any())
                    {
                        var update = _dbContext.Products.Where(p => p.Id == product.Id).FirstOrDefault();
                        update.LicenseNum = licenses.Count();
                        _dbContext.SaveChanges();
                    }
                }
            }
        }

        private string GetLicenseTypeName(string id, string module)
        {
            var licenseTypes = GetLicenseType();
            if (licenseTypes != null && licenseTypes.Any())
            {
                var licenseType = licenseTypes.FirstOrDefault(predicate: l => l.TypeId == id && l.Module == module);
                if (licenseType != null)
                    return licenseType.TypeName;
            }
            return string.Empty;
        }
    }
}

